package com.devmindset.legoframework.client.mvc.binding;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Default <code>Model</code> implementation.
 */
@SuppressWarnings("serial")
public class BaseModel implements Model, Serializable {
  
  /**
   * RCP map.
   */
  private RpcMap map;

  /**
   * Creates a new model data instance.
   */
  public BaseModel() {
  }

  /**
   * Creates a new model with the given properties.
   * 
   * @param properties the initial properties
   */
  public BaseModel(Map<String, Object> properties) {
    super();
    setProperties(properties);
  }
  
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public <X> X get(String property) {
    return map == null ? null : (X) map.get(property);
  }
  
  /**
   * Gets the property.
   * 
   * @param <X> the type
   * @param property the property
   * @param valueWhenNull the value to be used when null
   * 
   * @return the property
   */
  @SuppressWarnings("unchecked")
  public <X> X get(String property, X valueWhenNull) {
    X value = (X) get(property);
    return (value == null) ? valueWhenNull : value;
  }
  
  /**
   * {@inheritDoc}
   */
  public Map<String, Object> getProperties() {
    HashMap<String, Object> newMap = new HashMap<String, Object>();
    if (map != null) {
      newMap.putAll(map.getTransientMap());
    }
    return newMap;
  }
  
  /**
   * {@inheritDoc}
   */
  public Collection<String> getPropertyNames() {
    Set<String> set = new HashSet<String>();
    if (map != null) {
      set.addAll(map.keySet());
    }
    return set;
  }
  
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public <X> X remove(String property) {
    return map == null ? null : (X) map.remove(property);
  }
  
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public <X> X set(String property, X value) {
    if (map == null) {
      map = new RpcMap();
    }
    return (X) map.put(property, value);
  }

  /**
   * Sets the properties.
   * 
   * @param properties the properties
   */
  public void setProperties(Map<String, Object> properties) {
    for (String property : properties.keySet()) {
      set(property, properties.get(property));
    }
  }

  /**
   * Returns the map.
   *
   * @return the map
   */
  public RpcMap getMap() {
    return map;
  }

  /**
   * Sets the map.
   *
   * @param map the map to set
   */
  public void setMap(RpcMap map) {
    this.map = map;
  }
  
}